#!/usr/bin/python
# -*- coding: utf-8 -*-

#This file is part of pyLot library.
#
# pyLot is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyLot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pyLot.  If not, see <http://www.gnu.org/licenses/>.

__author__ = u'Pierre Puiseux, Guillaume Baty'
__copyright__ = u"Copyright 2011-2012 (C) andheo, Université de Pau et des Pays de l'Adour"
__credits__ = [u'Pierre Puiseux', u'Guillaume Baty']
__license__ = "GNU Lesser General Public License"

__all__ = [u'GuiProcess']

import sys

from pyLot.core import (ENCODING, hardbook, get_data, NullWriter, check_implements,
                        check_type)

from _pylot.qtgui.tools import generate_pyfile_from_uifile
from _pylot.qtgui.default.impl_widget import Widget
from _pylot.qtgui.widgets.gui_textview  import GuiTextView

from Qt4 import QtGui
from Qt4.QtCore import (SIGNAL, QMutexLocker, QMutex)

generate_pyfile_from_uifile(__name__,
  src=hardbook(u'uifiles', u'process.ui'),
  dest=get_data(__name__, u'_gui_process.py'))

from _gui_process import Ui_GuiProcess
class GuiProcess(QtGui.QWidget, Ui_GuiProcess, Widget, NullWriter):
  u"""
  GuiProcess provides a widget used to display process outputs.
  The widget is split into two views for standard and error outputs.
  """
  identifier = 'pyLot.widget.gui_textview'

  def __init__(self, stdout=None, stderr=None):
    QtGui.QWidget.__init__(self)
    Widget.__init__(self)
    self.running = False
    self.setupUi(self)

    if stdout is None :
      stdout = GuiTextView()
    else :
      check_type(u'stdout', stdout, GuiTextView)
    if stderr is None :
      stderr = GuiTextView()
    else :
      check_type(u'stderr', stderr, GuiTextView)

    self._stdout = stdout
    self._stderr = stderr

    self.layout_stdout.addWidget(self._stdout)
    self.append(self._stdout)

    self.layout_stderr.addWidget(self._stderr)
    self.append(self._stderr)

    self.splitter_moved = False

    self.command = None
    self.command_group = None
    self.process = None

    self._auto_scroll_output = True
    self._auto_scroll_error = True

    self.connect(self.splitter, SIGNAL('splitterMoved(int,int)'),
                 self._onSplitterSplitterMoved)

  _lock_process = QMutex()

  def _getrunning (self):
    lock = QMutexLocker(self._lock_process)
    value = self._running
    return value

  def _setrunning(self, value):
    lock = QMutexLocker(self._lock_process)
    self._running = value

  running = property(fget=_getrunning, fset=_setrunning)
  stdout = property(fget=lambda self:self._stdout)
  stderr = property(fget=lambda self:self._stderr)

  def setSplitterState (self, state):
    u"""
    :param state: a splitter state (QByteArray given by QSplitter.saveState for example)
    :type state: QByteArray
    """
    self.splitter.restoreState(state)

  def getSplitterState (self):
    return self.splitter.saveState()

  def write(self, text, style=u'std'):
    self._stdout.write(text, style)
    self._stderr.write(text, style)

  def stdout (self, s):
    self._stdout.write(s)

  def stderr (self, s):
    self._stderr.write(s)

  def _onSplitterSplitterMoved (self, pos, idx):
    self.splitter_moved = True

  def _updateOutText(self):
    t = str(self.process.readAllStandardOutput()).decode(ENCODING, u'replace')
    self.stdout(t)

    if self._auto_scroll_output is True :
      self._stdout.lockView()
    else :
      self._stdout.lockView(False)

  def _updateErrText(self):
    t = str(self.process.readAllStandardError()).decode(ENCODING, u'replace')
    self.stderr(t)

    if self._auto_scroll_error is True :
      self._stderr.lockView()
    else :
      self._stderr.lockView(False)

  def connectProcess (self, command_group, command, process_handler):
    self.running = True
    self.command_group = command_group
    self.process = command.thread.thread
    self.command = command

    self.connect(self.process, SIGNAL("readyReadStandardOutput()"),
                   self._updateOutText)
    self.connect(self.process, SIGNAL("readyReadStandardError()"),
                   self._updateErrText)

  def disconnectProcess (self, command_group):
    # Reset process variables
    self.command = None
    self.command_group = None
    self.process = None
    self.running = False

  def lockView (self, boolean):
    self._auto_scroll_error = boolean
    self._auto_scroll_output = boolean

  def changeBackgroundColor (self, text_edit=None,
                             color=QtGui.QColor(255, 255, 255)):
    if text_edit is None :
      text_edit = [self._stdout, self._stderr]

    for widget in text_edit :
      widget.changeBackgroundColor(color)

  def clearOutput (self):
    self._stdout.clear()

  def clearError (self):
    self._stderr.clear()

  def clear(self):
    self.clearOutput()
    self.clearError()

  def cancelProcess (self):
    command_group = self.command_group
    #self.controller.cancelProcess(self, self.command_group)
    if command_group :
      for cmd in command_group.cmds :
        cmd.kill()
      self.write(tr_(u'\nprocess aborted'), u'warn')


def main(args):
  app = QtGui.QApplication(args)
  win = QtGui.QMainWindow()

  widget = GuiProcess()
  win.setCentralWidget(widget)
  for tool_bar in widget.tool_bars :
    win.addToolBar(tool_bar)
  for menu in widget.menus :
    win.menu_bar.addMenu(menu)

  if widget.pref :
    widget.pref.show()

  widget.write(u'both: salut \n', u'title')
  widget.stdout(u'std: ¡ ça marche ! συγχαρητήρια ! 祝賀 !', u'warn')
  widget.stderr(u'err: ¡ ça marche ! συγχαρητήρια ! 祝賀 !', u'info')

  win.show()

  return app.exec_()

if __name__ == u"__main__":
  main(sys.argv)
  import doctest
  doctest.testmod()
